{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Результаты"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Отсортированы от лучших к худшим.\n",
    "\n",
    "##### FaceShifter https://arxiv.org/pdf/1912.13457.pdf \n",
    "Самый хронологически последний пейпер. Метод делает всё, что надо - сохраняет окружение, освещение, выражение лица - заменяет только \"самого человека\". Умеет учитывать посторонние предметы, которые частично закрывают лицо. Примеры выглядят впечатляюще. Судя по всему, лучший метод из существующих. И еще одно крутое его свойство, что ему не требуется никакой разметки вообще - просто большой датасет самих лиц. Недостаток - ему требуется претрейнед сеть для face detection в качестве метода кодирования лиц и игнорирования окружения. Но это вроде бы небольшой недостаток, потому что вряд ли будет трудно найти такую сетку.\n",
    "\n",
    "##### IP-GAN (автор не дал никакого названия - придумал сам) https://arxiv.org/abs/1803.11182\n",
    "По своим возможностям как FaceShifter, но 1) ему требуется датасет лиц, в котором отмечены пары или наборы картинок с одним и тем же человеком; 2) он возможно хуже умеет справляться с посторонними предметами, которые перекрывают лицо - хотя можно добавить второй стейдж FaceShifter, может быть это сработает. Зато здесь не требуются никакие pretrained модели, всё можно натренировать с нуля. Примеры тут тоже выглядят очень хорошо (хотя все примеры в статье \"удобные\", нет особо трудных). В статье не указана архитектура самих нейронок - поэтому если бы я реализовывал этот метод, я бы взял то, что предлагается в FaceShifter, либо поискал бы готовые реализации на github.\n",
    "\n",
    "##### FSGAN https://arxiv.org/pdf/1908.05932.pdf\n",
    "Тоже показывает очень крутые результаты (примеры из статьи), умеет \"дорисовывать\" части лица, которые были скрыты на лице-источнике, справляется со всякими перекрытиями вроде волос, рук или масок. Я поместил этот метод только на третью позицию потому, что он мне показался очень сложным в реализации, много компонентов: реккурентный генератор, который поворачивает лицо, сегментатор, генератор-дорисовыватель недостающих частей лица, и еще один генератор, который блендит лицо в целевую картинку. Кажется, всё это будет весьма тяжело натренировать. Еще недостаток - требуется разметка для сегментации лица и волос. А так, если преодолеть все эти трудности, возможно это будет работать не хуже, чем FaceShifter.\n",
    "\n",
    "##### RSGAN https://arxiv.org/pdf/1804.03447.pdf\n",
    "Этот метод на самом деле не подходит вообще, потому что он не сохраняет мимическое выражение оригинального лица, заменяет его на мимику лица, которое мы вставляем. Кроме того, ему тоже нужна разметка сегментации. И еще, этот метод имеет дополнительную фичу - тут явно кодируются всякие свойства типа цвета волос/бровей - и таким образом человек может поменять значения этого вектора и таким образом \"поредактировать\" результат на свое усмотрение. Прикольная фича, но сейчас не нужна.\n",
    "\n",
    "##### FSNet https://arxiv.org/pdf/1811.12666.pdf\n",
    "Это похоже на RSGAN - тоже сегментация + автоэнкодеры для лица и контекста + GAN, тоже не сохраняется оригинальная мимика. Судя по примерам, результат выглядит ощутимо хуже, чем RSGAN. Возможно, это был самый первый метод, который заменял лица произвольных людей."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Лог\n",
    "Дальше идут заметки, которые я делал в процессе. Там больше про ход моих мыслей. Так что можно не читать, если не нужно узнать, как именно я искал, что нашел и что думал."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### День 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "вот интересный пример того, как faceswap делается моделью, специальной натренированной под конкретных людей: https://github.com/joshua-wu/deepfakes_faceswap\n",
    "\n",
    "идея тут в том, что для каждого лица тренируется свой автоэнкодер, но энкодер у них общий, а декодеры разные. надо понимать, энкодер таким образом учится извлекать персона-независимые признаки - поворот головы, мимическое выражение и т.д., а декодер учится отображать эти параметры в лицо конкретного человека. отыскать бы пейпер...\n",
    "\n",
    "и это вообще-то не GAN - тут нет генератора и дискриминатора, это просто хитрое использование автоэнкодеров"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ооо, это прям справочник всевозможных GANs: https://github.com/eriklindernoren/PyTorch-GAN  \n",
    "Можно будет ознакомиться. Хотя скорее всего далеко не все они будут мне в тему. Большое спасибо автору за сводку abstract'ов в readme."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### День 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "После дня случайного блуждания по TDS и попыток самостоятельно придумать архитектуру, которая делала бы face-swap, я понял вот что. В этом домене есть по сути две переменные - лицо и контекст, которые замешаны в одну картинку. Лицо - это только \"идентичность\" человека, а выражение, эмоция - это скорее часть \"контекста\". То есть контекст - это окружающие объекты + выражение.\n",
    "\n",
    "Роль GAN в этой задаче может быть только в том, чтобы заточить функцию выдавать реалистичные результаты. Сам по себе GAN не может магически разделить переменные. Я думал о каком-то автоэнкодере, латентный код которого как-то разделяется на \"лицо\" и \"контекст\", но потом я понял, что в моих фантазиях отсутствует механизм, который дал бы этим кодам именно такой смысл. Поэтому получается, что в поисках пейперов нужно будет обращать внимание в первую очередь на то, как именно разделяется информация о контексте и лице."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/1908.05932.pdf FSGAN: Subject Agnostic Face Swapping and Reenactment; 2019 Aug  \n",
    "Тут лицо и контекст разделяются с помощью сегментации и по сути лицо1 просто вставляется в контекст2 вместо лица2, которое тоже вырезается сегментацией. Тут возникают несколько проблем - 1) лица имеют разную форму и ориентацию, 2) иногда какие-то части лица были скрыты и теперь показаны, 3) склеивать лицо1 и контекст2 нужно реалистично.\n",
    "\n",
    "Первая проблема решается очень интересно - находятся ключевые точки лица1 и лица2, строится нечто вроде нескольких промежуточных наборов ключевых точек, которые интерполируют преобразование от лица1 к лицу2, и затем RNN в несколько шагов поворачивает лицо1 в положение лица2.\n",
    "\n",
    "Вторая проблема (части лица, скрытые на картинке1, но видимые на картинке2) и третья (реалистичное склеивание с контекстом) решаются двумя сетями-генераторами, которые вроде как различаются только специфичными для них аугментациями и лоссами.\n",
    "\n",
    "Здесь разделение лица и контекста достигается по сути с помощью эвристик - между лицом и контекстом есть \"территориальная\" граница, а затем факт, что лицо это почти твердое тело, которое нужно повращать. И в этом \"фреймворке\" есть несколько нейронок, которые решают конкретные подзадачи. Довольно сложный дизайн - много компонентов. Но тренируется вроде как end-to-end, уже хорошо. Пейпер опубликован в августе 2019. Возможно это и есть текущий SOTA."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/1909.11573.pdf Deep Learning for Deepfakes Creation and Detection (survey); 2019 Sep  \n",
    "Обзор по методам подмены лиц и детекции подмены. Секция 2 перечисляет методы - все они основываются на том, что я нашел вчера, вот эту тему с энкодером и парой декодеров. После этого просто добавили GAN, а потом еще GAN с какими-то доп. фичами, но суть осталась та же - декодер тренируется под конкретное лицо. К сожалению, персона-независимых методов тут нет.  \n",
    "Секция 3 говорит о детекции фейков - мне это сейчас не интересно, пропускаю.  \n",
    "Секция 4 с дискуссиями вроде бы говорит в основном о детекции фейков, тоже пропускаю."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/1703.10593.pdf  Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks; 2018 Nov  \n",
    "Отсюда я узнал, что такое CycleGAN, который я уже встречал в текстах. Окей, это преобразование картинки из одного \"класса\" в другой и обратно с помощью нейронок, делающих обратные друг другу преобразования, а дискриминатор применяется для того, чтобы заставить эти нейронки-преобразователи делать результат похожим на требуемый класс. Красивая идея. Но думаю, что мне сейчас не полезная, потому что она не предлагает мне способа разделить \"лицо\" и \"контекст\". Просто плюсик к обзору в области GAN."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/1611.07004.pdf Image-to-Image Translation with Conditional Adversarial Networks; 2018 Nov  \n",
    "Команда авторов пересекается с предыдущим пейпером. Отсюда я узнал, что же такое cGAN, который я тоже не раз видел уже. Если я правильно понял, суть в том, что картинки тут тоже отображаются из одного \"класса\" в другой, но к входным данным еще примешивается случайный шум, который позволяет генерировать разнообразные варианты из одного и того же входного примера. Прикольно, хотя не уверен, что понял на 100% правильно. В любом случае, к face swap это видимо не имеет отношения."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### День 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Пошел на arxiv, набрал там все заинтересовавшие статьи, которые выдаются по запросам \"face swap\", \"faceswap\", \"deep fake\", \"deepfake\", \"identity swap\". К сожалению, просто \"face\" выдает 16к статей - слишком много, чтобы можно было их пролистать. Сразу могу сказать, что кроме того, что я уже видел, вроде бы только одна или две потенциально полезные статьи есть. Поехали..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/abs/2006.12247 Disrupting Deepfakes with an Adversarial Attack that Survives Training; 2020 Jun  \n",
    "Метод \"защиты\" картинки от дипфейка - добавляется какой-то выученный шум, который позволяет как-то отличить дипфейк, если его сделают на зашумленной таким методом картинке. Прикольно, но дальше не вникал."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/abs/2006.07421 Defending against GAN-based Deepfake Attacks via Transformation-aware Adversarial Faces; 2020 Jun  \n",
    "Еще один способ защиты от дипфейка - тоже добавляется шум, который вызывает деградацию результата при подмене лица. Окей."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/abs/2006.07397 The DeepFake Detection Challenge Dataset; 2020 Jun  \n",
    "Это видимо датасет, использовавшийся для этого самого соревнования по deepfake detection на Kaggle. Возможно пригодится."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/abs/2005.05535 DeepFaceLab: A simple, flexible and extensible face swapping framework; May 2020  \n",
    "Описывает дизайн софта, который позволяет пользователю не-специалисту обучать вот эти самые автоэнкодеры под конкретную пару людей."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/2001.00179.pdf DeepFakes and Beyond: A Survey of Face Manipulation and Fake Detection; 2020 Jun  \n",
    "Обзор по разным видам манипуляций над лицами. К сожалению, в секции, посвященной подмене лиц, не нашел ссылок на методы генерации - только датасеты и методы детекции."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### День 4\n",
    "Ничего не делал, слишком загруженный день был"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### День 5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/1912.13457.pdf FaceShifter: Towards High Fidelity And Occlusion Aware Face Swapping;  2020 Jun  \n",
    "Во, наконец-то что-то подходящее. Как это работает:  \n",
    "Есть претрейнед модель для фейс детекшна. Ее последний вектор перед FC используется как код лица. Также есть UNet-like сеть для кодирования \"контекста\" в виде нескольких feature maps разных скейлов, и сеть-генератор, которая соединяет эти два кода, используя свою разновидность attention. Как я понял, фейс-детекшн не тренируется, а просто используется как готовая функция, а энкодер контекста и генератор тренируются с применением нескольких лоссов: adversarial лосс применяется к результату генератора, чтобы сделать его реалистичным, затем два лосса, заставляющих систему сохранять код лица и код контекста - фейс-детекшн модель должна выдавать одинаковые коды на картинке с вставляемым лицом и на картинке-результате, а энкодер контекста аналогично должен выдавать одинаковые коды на картинке, куда мы вставляем лицо, и на картинке-результате. И еще есть лосс, который применяется только когда две исходные картинки с требуемым лицом и требуемым контекстом - это одна и та же картинка - просто попиксельный L2.\n",
    "\n",
    "Далее идет второй стейдж, задача которого - справиться с посторонними предметами типа очков, волос, головных уборов и т.п. Авторы заметили, что проблемы с посторонними предметами есть даже если две входные картинки - одна и та же картинка. Видимо, это последствие attention. И они использовали это наблюдение - взяли UNet-like сеть, дали ей результат первого стейджа +(конкат) reconstruction error от first-stage(X1,X1), и тренировали так, чтобы минимизировался reconstruction error второй стейджа если две входные картинки - одна и та же картинка, чтобы сохранялся код лица, и минимизировать L1 между выходами первого и второго стейждев - то есть, они будут похожи, за исключением аутлаеров, которые и есть вот эти ошибки на посторонних предметах.\n",
    "\n",
    "Красивый подход, мне он нравится куда больше, чем FSGAN, потому что он намного проще. Кроме того, FSGAN требует датасет с сегментацией лиц и волос, а тут похоже что вообще никакой разметки не нужно - просто датасет лиц и всё. Ну и наконец, авторы репортят, что их результат лучше, чем FSGAN - так что сейчас это топ-1 для меня."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В этой работе я прошелся по ссылкам - тут упоминается много других методов. Часть из них я не смотрел даже - либо потому, что не нашел пейпер в открытом доступе, либо потому, что дата публикации до 2012 года - не верю, что в до-CNN эпоху были методы, достойные внимания сейчас."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/1811.12666.pdf FSNet: An Identity-Aware Generative Model for Image-based Face Swapping; Nov 2018  \n",
    "Тут нужна разметка - сегментация лица и кейпоинты лица - так лицо отделяется от контекста. Код вставляемого лица (целевого) создается автоэнкодером. На картинке, куда вставляется целевое лицо, с помощью маски удаляется оригинальное лицо. Потом генератор берет латентный код целевого лица, целевую картинку с вырезанным оригинальный лицом, и из этого собирает результат. Вся информация о выражении оригинального лица тут, как я понял, умножается на ноль, и поэтому тут сохранить его не получится, будет \"унаследовано\" выражение целевого лица с картинки-источника. Припоминаю, что видел где-то в более свежий пейперах критику насчет всяких артефактов, неспособности справиться с разной формой целевого и оригинального лиц, и т.д.. В общем, в принципе под формулировку моей задачи подходит, но это скорее всего не SOTA."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/1804.03447.pdf RSGAN: Face Swapping and Editing using Face and Hair Representation in Latent Spaces; Apr 2018  \n",
    "Идея такая - кодируем отдельно лица и контексты и меняем местами при декодировании. Лицо и контекст разделяются с помощью сегментации, а кодируется через VAE - то есть два автоэнкодера учатся реконструировать соотв лица и контексты. А латентные репрезентации используются генератором, который их склеивает. Генератор тренируется как стандартный GAN. И еще дополнительно тут есть классификатор, который определяет всякие визуальные атрибуты типа вида прически, цвета бровей и т.д. - признаки, определенные классификатором, используются как дополнительные входные данные автоэнкодеров. Это нужно, чтобы при реконструкции лица человек мог подменить эти признаки на какие ему хочется, и таким образом \"редактировать\" результат. От предыдущего FSNet отличия - это вот эта возможность \"редактировать\" и то, что контекст тоже кодируется автоэнкодером - то есть вероятно можно ожидать более \"гладкого\" склеивания между лицом и контекстом.\n",
    "\n",
    "Если выбросить классификатор и возможность \"редактирования\", то этот метод немного лучше выглядит, чем FSNet, но имеет все тот же недостаток, который кажется мне ключевым - тут явным образом стирается информация об оригинальном выражении лица. Это же наверняка еще и артефакты типа неправильного освещения может дать..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/1704.06729.pdf On Face Segmentation, Face Swapping, and Face Perception; Apr 2017  \n",
    "Более ранняя работа уже известного мне автора FSGAN. Тут сначала каким-то уже существующим методом 3DMM выделяются трехмерные кейпоинты (много видел упоминаний, но не смотрел, что за метод). Причем есть метод для оценки ориентации, метод для оценки выражения - и в этой работе эти оценки соединяются в один вектор по сути линейной комбинацией. Так делается для обоих картинок. Потом берут текстуру целевого лица и билинейной интерполяцией \"натягивают\" на форму оригинального лица. Затем используют сетку-сегментатор, чтобы понять, куда можно вставлять новую текстуру, а где есть какое-то препятствие. А потом каким-то тоже уже существующим методом блендят новую текстуру в целевой контекст - это не ML метод, там какое-то хитрое уравнение решается. Я посмотрел на примеры работы их метода - и выглядит так, что скорее сохраняется выражение лица с картинки-источника. Странно, если я правильно понял метод, этого происходить как раз наоборот не должно.\n",
    "\n",
    "Видимо, в своей последующей работе FSGAN он как раз и развивает этот метод, заменяя эвристические модели на ML, и попутно решая проблемы с дорисовыванием частей лица, которые видны на целевой картинке, но были скрыты на картинке-источнике."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### День 6"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/1611.09577.pdf Fast Face-swap Using Convolutional Neural Networks; Jul 2017  \n",
    "Подмена лица формулируется как замена \"стиля\" картинки - \"стиль\" здесь это лицо, а окружение, освещение и выражения лица - это \"содержание\", которое они стремятся сохранить. Сначала картинки выравниваются друг относительно друга, используя кейпоинты - вычисляется оптимальный аффинный трансформ от каждого вектора кейпоинтов к вектору, соответствующему фронтальному ракурсу, картинки варпаются. Затем их нейронка преобразует лицо и картинка варпается обратно. Нейронка-преобразователь тренируется специальным хитрым лоссом, который использует близость feature maps из VGG как метрику сохранения \"контента\" и косинусное расстояние между двумя наиболее похожими патчами результата и картинки-источника - как метрику схожести \"стиля\".\n",
    "\n",
    "А стоп - эта модель тренируется под замену на конкретного человека, т.е. целевое лицо \"зашито\" в модель на этапе тренировки - это не интересно, пропускаю."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/2004.11138.pdf The Creation and Detection of Deepfakes: A Survey;  May 2020  \n",
    "Обзор. Большая статья, посвященная разным аспектам дипфейков (и картинки, и видео, и замена эмоции/ориентации). Я только пробежался по нужному мне разделу, ничего нового не нашел, да там и не перечислялись сами методы, больше про какие-то конкретные элементы... Прошелся также по половине списка референсов - увидел пару знакомых названий, но остальное было не по теме. Остановился, пошел дальше."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/pdf/2004.07532.pdf DeepFakes Evolution: Analysis of Facial Regions and Fake Detection Performance; Jul 2020  \n",
    "Обзор, но тут только базы данных и методы детекции дипфейков есть."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://arxiv.org/abs/1803.11182 Towards Open-Set Identity Preserving Face Synthesis; Mar 2018  \n",
    "Вот это очень похоже на то, что я пытался придумать еще в самом начале. И также похоже на тот метод, который я пока держу в голове как лучший. Тут есть два энкодера - один для лица, один для контекста. Потом кода лица и код контекста конкатенируются и объединенный код идет в генератор. В данных нужны размеченные наборы изображений одного и того же человека. Тогда тренируется классификатор, который смотрит на две картинки и говорит, это один и тот же человек или нет. Таким образом тренируется стек энкодер лица + генератор: KL loss + real/fake discriminator + same/different identity classifier.\n",
    "\n",
    "Для кодирования контекста они стремятся избежать потребности в разметке данных, потому что это слишком сложно. Поэтому они тут хитрят - они в целом используют просто reconstruction loss для результатов генератора, но для примеров, когда identity был заменен, просто дают этому лоссу меньший вес (0.1).\n",
    "\n",
    "И третье, у них проблема с тем, что датасеты, в которых размечены same identity, как правило маленькие по размеру, недостаточно разнообразные, и поэтому они просто набрали 1М случайных картинок, вырезали из них лица, и дополнили ими трейн сет. Поскольку тут нет разметки same identity, они либо использовали эти картинки как целевые (куда вставляется лицо), либо как картинки-источники (откуда лицо берется), но при этом не обновляли identity encoder и same identity classifier.\n",
    "\n",
    "В целом, я верю в этот подход примерно так же, как в тот FaceShifter, который я предварительно назначил как лучший, но ему требуются размеченные данные - чтобы были указаны наборы картинок, где один и тот же человек изображен. В принципе можно взять фильмы, нарезать лиц из кадров, и в рамках одного фильма запустить какую-нибудь претрейнед сеть для same identity - даже без ручной правки там скорее всего достаточно чистый датасет получится."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Всё, пора подводить итоги."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "apds",
   "language": "python",
   "name": "apds"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
